package com.starsky.common.utils.encrypt;

import com.starsky.common.constant.BaseConstant;
import org.apache.commons.lang3.StringUtils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;

/**
 * @author wansh
 * @version 1.0
 * @des md5加密
 * @date 2020/9/19 21:55
 * @email 1057718341@qq.com
 */
public class MD5Utils {

    private String inStr;

    private MessageDigest md5;

    public MD5Utils(String inStr) {
        this.inStr = inStr;
        try {
            this.md5 = MessageDigest.getInstance("MD5");
        } catch (Exception e) {
            System.out.println(e.toString());
            e.printStackTrace();
        }
    }

    public final static String MD5(String content) {
        //用于加密的字符
        char md5String[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                'A', 'B', 'C', 'D', 'E', 'F'};
        try {
            //使用平台的默认字符集将此 String 编码为 byte序列，并将结果存储到一个新的 byte数组中
            byte[] btInput = content.getBytes();

            //信息摘要是安全的单向哈希函数，它接收任意大小的数据，并输出固定长度的哈希值。
            MessageDigest mdInst = MessageDigest.getInstance("MD5");

            //MessageDigest对象通过使用 update方法处理数据， 使用指定的byte数组更新摘要
            mdInst.update(btInput);

            // 摘要更新之后，通过调用digest（）执行哈希计算，获得密文
            byte[] md = mdInst.digest();

            // 把密文转换成十六进制的字符串形式
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {   //  i = 0
                byte byte0 = md[i];  //95
                str[k++] = md5String[byte0 >>> 4 & 0xf];    //    5
                str[k++] = md5String[byte0 & 0xf];   //   F
            }

            //返回经过加密后的字符串
            return new String(str);

        } catch (Exception e) {
            return null;
        }
    }

    public static String string2Md5(String s) {
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        byte[] md5Bytes = md5.digest(s.getBytes());
        StringBuffer hexValue = new StringBuffer();
        for (int i = 0; i < md5Bytes.length; i++) {
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16)
                hexValue.append("0");
            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();
    }


    private String compute() {
        char[] charArray = this.inStr.toCharArray();
        byte[] byteArray = new byte[charArray.length];
        for (int i = 0; i < charArray.length; i++) {
            byteArray[i] = (byte) charArray[i];
        }
        byte[] md5Bytes = this.md5.digest(byteArray);
        StringBuffer hexValue = new StringBuffer();
        for (int i = 0; i < md5Bytes.length; i++) {
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16) {
                hexValue.append("0");
            }
            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();
    }

    /**
     * 用户登录时输入的密码与数据库加密密码进行比较
     *
     * @param plaintextPwd 用户输入的明文密码
     * @param salt         随机“佐料” salt
     * @param md5Pwd       数据库中加密后的密码
     * @return
     */
    public static boolean compare(String plaintextPwd, String salt, String md5Pwd) {
        MD5Utils md5 = new MD5Utils(plaintextPwd);
        // 用MD5第一次加密
        String pwd = md5.compute();
        pwd = pwd + salt;
        // 再次用MD5加密
        MD5Utils m = new MD5Utils(pwd);
        // 得到最终密文
        String npwd = m.compute().toUpperCase();
        return npwd.equals(md5Pwd);
    }

    /**
     * 密码盐 加密
     *
     * @param plaintextPwd 明文密码
     * @param salt         用户名
     * @return
     */
    public static String enCode(String plaintextPwd, String salt) {
        plaintextPwd = StringUtils.isBlank(plaintextPwd) ? BaseConstant.DEFAULT_PWD : plaintextPwd;
        MD5Utils md5 = new MD5Utils(plaintextPwd);
        // 用MD5第一次加密
        String pwd = md5.compute();
        pwd = pwd + salt;
        // 再次用MD5加密
        MD5Utils m = new MD5Utils(pwd);
        // 得到最终密文
        String npwd = m.compute().toUpperCase();
        return npwd;
    }

    /**
     * 字符编码
     */
    private static String charset = "UTF-8";

    /**
     * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
     */
    @SuppressWarnings("rawtypes")
    public static String createSign(SortedMap<String, String> packageParams, String elecSign) {
        StringBuffer sb = new StringBuffer();
        Set es = packageParams.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + elecSign);
        System.out.println("md5 sb:" + sb);
        String sign = MD5Encode(sb.toString(), charset).toUpperCase();
        System.out.println("签名:" + sign);
        return sign;
    }

    public static String createSignTest(SortedMap<String, String> packageParams, String elecSign) {
        StringBuffer sb = new StringBuffer();
        Set es = packageParams.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + elecSign);
        System.out.println("md5 sb:" + sb);
        String sign = MD5Encode(sb.toString(), charset).toUpperCase();
        System.out.println("原串：" + sb + ",签名：" + sign);
        return sign;
    }

    private static String byteArrayToHexString(byte b[]) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            resultSb.append(byteToHexString(b[i]));
        }

        return resultSb.toString();
    }

    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n += 256;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    public static String MD5Encode(String origin, String charsetname) {
        String resultString = null;
        try {
            resultString = new String(origin);
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (charsetname == null || "".equals(charsetname)) {
                resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
            } else {
                resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
            }
        } catch (Exception exception) {
        }
        return resultString;
    }

    private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};


    public static void main(String[] args) {
        System.out.println(string2Md5("123456"));

        String pss = MD5("123456" + "054e9751b96e45e5ac8226e076603655");
        System.out.println(pss);
    }

}
